package helper

import (
	"errors"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"regexp"
	"strings"
)

var (
	ErrNotFound = errors.New("not found")
)

var (
	systemRegexp                  = regexp.MustCompile(`<td.*?System.*?<td.*?>(.*?)</td>`)
	serverAPIRegexp               = regexp.MustCompile(`<td.*?Server API.*?<td.*?>(.*?)</td>`)
	registeredPhpStreamsRegexp    = regexp.MustCompile(`<td.*?Registered PHP Streams.*?<td.*?>(.*?)</td>`)
	registeredStreamFiltersRegexp = regexp.MustCompile(`<td.*?Registered Stream Filters.*?<td.*?>(.*?)</td>`)
	phpVersionRegexp              = regexp.MustCompile(`<td.*?PHP Version.*?<td.*?>(.*?)</td>`)
	documentRootRegexp            = regexp.MustCompile(`<td.*?\$_SERVER\['DOCUMENT_ROOT'].*?<td.*?>(.*?)</td>`)
	disableFunctionsRegexp        = regexp.MustCompile(`<td.*?disable_functions.*?<td.*?>(.*?)</td>`)
)

type PhpInfoParser struct {
	data []byte
}

func NewPhpInfoParser(data []byte) *PhpInfoParser {
	return &PhpInfoParser{
		data: data,
	}
}

func (p *PhpInfoParser) reMatch(re *regexp.Regexp) (string, error) {
	result := re.FindSubmatch(p.data)
	if len(result) != 2 {
		return "", ErrNotFound
	}
	checked := strings.TrimSpace(string(result[1]))
	return checked, nil
}

func (p *PhpInfoParser) GetOsInfo() (*expbase.OSInfo, error) {
	checked, err := p.reMatch(systemRegexp)
	if err != nil {
		return nil, err
	}
	parts := strings.Split(checked, " ")
	if len(parts) < 2 {
		return nil, ErrNotFound
	}
	return &expbase.OSInfo{
		Os:   parts[0],
		Arch: parts[len(parts)-1],
	}, nil
}

func (p *PhpInfoParser) GetPhpInfo() (*expbase.PhpInfo, error) {
	serverApi, err := p.reMatch(serverAPIRegexp)
	if err != nil {
		return nil, err
	}
	registeredPhpStream, err := p.reMatch(registeredPhpStreamsRegexp)
	if err != nil {
		return nil, err
	}
	registeredStreamFilters, err := p.reMatch(registeredStreamFiltersRegexp)
	if err != nil {
		return nil, err
	}
	phpVersion, err := p.reMatch(phpVersionRegexp)
	if err != nil {
		return nil, err
	}
	documentRoot, err := p.reMatch(documentRootRegexp)
	if err != nil {
		return nil, err
	}
	disableFunctions, err := p.reMatch(disableFunctionsRegexp)
	if err != nil {
		return nil, err
	}
	disableFunctions = strings.TrimPrefix(disableFunctions, "<i>")
	disableFunctions = strings.TrimSuffix(disableFunctions, "</i>")
	var disableList []string
	if disableFunctions != "no value" {
		disableList = strings.Split(disableFunctions, ",")
	}
	return &expbase.PhpInfo{
		PhpVersion:              phpVersion,
		ServerAPI:               serverApi,
		DocumentRoot:            documentRoot,
		RegisteredPhpStreams:    strings.Split(registeredPhpStream, ","),
		RegisteredStreamFilters: strings.Split(registeredStreamFilters, ","),
		DisableFunctions:        disableList,
	}, nil
}
